# -*- coding: utf-8 -*-
"""
中性策略框架 | 邢不行 | 2024分享会
author: 邢不行
微信: xbx6660
"""
import os
import time
import ccxt

root_path = os.path.abspath(os.path.dirname(__file__))  # 返回当前文件路径

# 获取目录位置，不存在就创建目录
data_path = os.path.join(root_path, 'data')
if not os.path.exists(data_path):
    os.makedirs(data_path)

# 获取目录位置，不存在就创建目录
data_center_path = os.path.join(root_path, 'data', 'data_center')
if not os.path.exists(data_center_path):
    os.makedirs(data_center_path)

# 获取目录位置，不存在就创建目录
flag_path = os.path.join(root_path, 'data', 'flag')
if not os.path.exists(flag_path):
    os.makedirs(flag_path)


# 获取目录位置，不存在就创建目录
order_path = os.path.join(root_path, 'data', 'order')
if not os.path.exists(order_path):
    os.makedirs(order_path)


# 获取目录位置，不存在就创建目录
curve_path = os.path.join(root_path, 'data', 'curve')
if not os.path.exists(curve_path):
    os.makedirs(curve_path)

# =====debug模式。模拟运行程序，不会去下单
is_debug = False

# =====获取当前服务器时区，距离UTC 0点的偏差
utc_offset = int(time.localtime().tm_gmtoff / 60 / 60)  # 如果服务器在上海，那么utc_offset=8

# =====读取数据的核心数。根据自身服务器情况调整
njob = max(int(os.cpu_count() - 2), 1)  # 1, -1都是串行。0 无效会报错。2及以上使用多进程。
# njob = 1  # 1, -1都是串行。0 无效会报错。2及以上使用多进程。

# =====现货稳定币名单，不参与交易的币种
stable_symbol = ['BKRW', 'USDC', 'USDP', 'TUSD', 'BUSD', 'FDUSD', 'DAI', 'EUR', 'GBP', 'USBP', 'SUSD', 'PAXG', 'AEUR']

# =====特殊现货对应列表
special_symbol_dict = {
    'DODO': 'DODOX',  # DODO现货对应DODOX合约
    'LUNA': 'LUNA2',  # LUNA现货对应LUNA2合约
    '1000SATS': '1000SATS',  # 1000SATS现货对应1000SATS合约
}

# 现货下单最小金额限制，适当增加可以减少部分reb。默认10，不建议小于10，这会让你的下单报错，10是交易所的限制。
order_spot_money_limit = 10
# 合约下单最小金额限制，适当增加可以减少部分reb。默认5，不建议小于5，这会让你的下单报错，5是交易所的限制。
order_swap_money_limit = 5

# =====账号配置
account_config = {
    "账户1": {  # 账户名称，建议用英文，不要带有特殊符号
        "email": "xxxxxxx@outlook.com",  # 当前账户的邮箱
        "strategy_list": [  # 实盘前先回测一下，不要无脑跑案例策略，没人能保证案例策略能赚钱
            {
                "strategy": "Shift_Example",  # 策略名称。与strategy目录中的策略文件名保持一致。
                "offset_list": [0],  # 根据自己回测来决定。offset_list 配置错误，会影响选币和下单金额
                "cap_weight": 1,  # 资金权重。程序会自动根据这个权重计算你的策略占比，具体可以看1.8的直播讲解
                # 下面参数是官方提供的覆盖参数，一个短周期参数，一个长周期参数
                "param_list": [[7], [20]],  # 轮动因子的参数覆盖，目前只支持单策略。具体可以看2.1.9的直播讲解
            }
        ],
        # 全局配置改成账户策略配置
        "if_use_bnb_burn": True,  # 是否开启BNB燃烧，抵扣手续费
        "buy_bnb_value": 11,  # 买多少U的bnb来抵扣手续费。建议最低11U，现货最小下单量限制10U
        "if_transfer_bnb": False,  # 是否开启小额资产兑换BNB功能。仅现货模式下生效
        "black_list": ['BTCUSDT', 'ETHUSDT'],  # 黑名单。不参与交易的币种
        "white_list": [],  # 白名单。只参与交易的币种
        "leverage": 1,  # 杠杆。现货模式下：最大杠杆限制1.3倍。合约模式不做限制。
        "get_kline_num": 999,  # 获取多少根K线。这里跟策略日频和小时频影响。日线策略，代表999根日线k。小时策略，代表999根小时k
        "min_kline_size": 168,  # 最低要求b中有多少小时的k线。这里与回测一致。168：表示168小时
        "max_one_order_amount": 100,  # 最大拆单金额。
        "twap_interval": 2,  # 下单间隔
        "if_rebalance": True,  # 是否开启rebalance模式，默认True，表示开启，False表示不开启。
        "is_pure_long": False,  # 纯多设置，只有单账户跑纯多的时候使用(https://bbs.quantclass.cn/thread/36230)
        "is_ahead_calc": False,  # 是否提前30分钟计算全部offset资金曲线, 默认：False。注意：多账户多策略的时候，提前30分钟可能时间不够，建议设置False
        "hour_offset": '0m',  # 分钟偏移设置，可以自由设置时间，配置必须是kline脚本中interval的倍数。默认：0m，表示不偏移。15m，表示每个小时偏移15m下单。
        # 创建企业微信机器人 参考帖子: https://bbs.quantclass.cn/thread/10975
        # 配置案例  https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxxxxxxxxxxxxx
        "wechat_webhook_url": 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='
    },
}
for account, cfg in account_config.items():
    # 具体细节需要从轮动策略的配置里面读取
    if cfg['strategy_list'][0]['strategy'].startswith('Shift'):
        account_config[account]['is_shift'] = True
        # 获取轮动策略配置
        _shift_cls = __import__(f'shift.{cfg["strategy_list"][0]["strategy"]}', fromlist=('',))
        # 设置默认为非现货模式
        account_config[account]['has_spot_strategy'] = False
        # 遍历轮动的子策略
        for stg_name in list(_shift_cls.base_strategy_dict.keys()):
            _cls = __import__(f'strategy.{stg_name}', fromlist=('',))
            account_config[account]['is_day_period'] = True if _cls.hold_period[-1:] == 'D' else False
            # 只需要一个策略开启了现货模式，那么就含有现货策略
            if _cls.if_use_spot:
                account_config[account]['has_spot_strategy'] = True
                break
    else:
        account_config[account]['is_shift'] = False
        _cls = __import__(f'strategy.{cfg["strategy_list"][0]["strategy"]}', fromlist=('',))
        account_config[account]['is_day_period'] = True if _cls.hold_period[-1:] == 'D' else False
        account_config[account]['has_spot_strategy'] = False
        for stg in cfg["strategy_list"]:
            _cls = __import__(f'strategy.{stg["strategy"]}', fromlist=('',))
            if _cls.if_use_spot:
                # 只需要一个策略开启了现货模式，那么就含有现货策略
                account_config[account]['has_spot_strategy'] = True
                break
    # 计算当前账号下所有策略的资金权重总和
    all_cap_weight = sum(item["cap_weight"] for item in cfg["strategy_list"])
    # 遍历计算策略
    for stg in cfg["strategy_list"]:
        # 对每个策略的资金占比进行重新计算。当前资金权重 / 账户所有策略资金权重
        stg['cap_weight'] = stg['cap_weight'] / all_cap_weight

# =====交易所配置
# ===账户配置
apikey_config = {
    '账户1': {  # 与account_config配置的名称保持一致
        'apiKey': '',
        'secret': '',
    },
}


# 如果使用代理 注意替换IP和Port
proxy = {}
# proxy = {'http': 'http://127.0.0.1:7890', 'https': 'http://127.0.0.1:7890'}
exchange_basic_config = {
    'timeout': 30000,
    'rateLimit': 30,
    'enableRateLimit': True,
    'options': {
        'adjustForTimeDifference': True,
        'recvWindow': 50000,
    },
    'proxies': proxy,
    'is_pure_long': False
}
# 遍历账户配置，将所有账户的交易所配置，全部创建出来
account_list = list(account_config.keys())
for account in account_list:
    # account_config配置中有配对的apikey，才会创建交易所对象
    if account not in apikey_config:
        del account_config[account]
        continue
    _apikey = apikey_config[account]['apiKey']
    _secret = apikey_config[account]['secret']
    if _apikey and _secret:
        exchange_basic_config['apiKey'] = _apikey
        exchange_basic_config['secret'] = _secret
        # 在Exchange增加纯多标记(https://bbs.quantclass.cn/thread/36230)
        exchange_basic_config['is_pure_long'] = account_config[account]['is_pure_long']
        account_config[account]['exchange'] = ccxt.binance(exchange_basic_config)
    else:
        del account_config[account]

# =====全局报错机器人通知
# 创建企业微信机器人 参考帖子: https://bbs.quantclass.cn/thread/10975
# 配置案例  https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxxxxxxxxxxxxx
error_webhook_url = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key='


# =====本地电脑与服务器的时差
class GlobalVariable:
    diff_timestamp = 0

    def update_diff_time(self, _t):
        self.diff_timestamp = _t


# 存储这个全局变量
glob_var = GlobalVariable()
